/*
Copyright (C) 2009-2011 Xanadu Development Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "Buddies.h"
#include "Buddy.h"
#include "Channel.h"
#include "../tools/MySQLM.h"
#include "../tools/PacketCreator.h"
#include "../net/world/World.h"

Buddies::~Buddies() {
	for (hash_map<int, Buddy*>::iterator iter = buddies.begin(); iter != buddies.end(); iter++)
		delete iter->second;
}

void Buddies::add(int id, string name, int channel) {
	Buddy* buddy = new Buddy();
	buddy->setBuddyid(id);
	buddy->setName(name);
	buddy->setChannel(channel);
	buddies[buddy->getBuddyid()] = buddy;
}

int Buddies::getSize() {
	return (int)buddies.size();
}

hash_map <int, Buddy*>* Buddies::getList() {
	return &buddies;
}

Buddy* Buddies::getBuddy(int buddyid) {
	if(buddies.find(buddyid) == buddies.end()) {
		return 0;
	}
	return buddies[buddyid];
}

void Buddies::accept(int buddyid) {
	mysqlpp::Connection::thread_start();
	mysqlpp::Connection* conn = MySQL::getInstance()->getPool()->grab();
	mysqlpp::Query query = conn->query();
	
	query << "INSERT INTO buddylist (charid, buddyid) VALUES (" << player->getID() << ", " << buddyid << ")";
	query.execute();

	Player* buddy = player->getChannel()->getWorld()->getPlayerByID(buddyid);
	if (buddy) {
		if (buddy->getBuddyList()->getBuddy(player->getID())) {
			buddy->getBuddyList()->getBuddy(player->getID())->setChannel(player->getChannel()->getID());
			buddy->send(PacketCreator().updateBuddyChannel(player->getID(), player->getChannel()->getID()));
		}
		if (!getBuddy(buddyid)) {
			add(buddyid, buddy->getName(), buddy->getChannel()->getID());
		}
	}
	if (!getBuddy(buddyid)) {
		add(buddyid, MySQL::getInstance()->getString("characters", "ID", buddyid, "name"), -1);
	}
	MySQL::getInstance()->getPool()->release(conn);
	mysqlpp::Connection::thread_end();
	player->send(PacketCreator().buddyList(player));
}

void Buddies::add(string name) {
	if (buddies.size() >= player->getBuddyListSize()) {
		// Buddy list full
		player->send(PacketCreator().buddyError(0x0B));
		return;
	}
	mysqlpp::Connection::thread_start();
	mysqlpp::Connection* conn = MySQL::getInstance()->getPool()->grab();
	mysqlpp::Query query = conn->query();

	query << "SELECT "
		<< "c.id, c.name, u.gm, c.buddylist_size AS buddylist_limit, "
		<< "(SELECT COUNT(b.id) FROM buddylist b WHERE b.charid = c.id) AS buddylist_size "
		<< "FROM characters c "
		<< "INNER JOIN accounts u ON c.userid = u.id "
		<< "WHERE c.name = " << mysqlpp::quote << name;

	mysqlpp::StoreQueryResult res = query.store();
	if (res.size() == 0) {
		// Player does not exist
		player->send(PacketCreator().buddyError(0x0F));
		return;
	}
	if ((int) res[0][2] > 0 && !player->isGM()) {
		// GM cannot be in buddy list unless the player is a GM
		player->send(PacketCreator().buddyError(0x0E));
		return;
	}
	int buddyid = res[0][0];

	if (buddies.find(buddyid) != buddies.end()) {
		// Already in buddy list
		player->send(PacketCreator().buddyError(0x0D));
		return;
	}
	query << "INSERT INTO buddylist (charid, buddyid) VALUES (" << player->getID() << ", " << buddyid << ")";
	query.execute();
	Player* buddy = player->getChannel()->getWorld()->getPlayerByName(name);
	add(buddyid, name, -1);
	if (buddy) {
		if(buddy->getBuddyList()->getBuddy(player->getID())) {
			buddy->getBuddyList()->getBuddy(player->getID())->setChannel(player->getChannel()->getID());
			buddy->send(PacketCreator().buddyList(buddy));
			getBuddy(buddyid)->setChannel(buddy->getChannel()->getID());
		} else {
			buddy->send(PacketCreator().buddyApprove(player->getID(), player->getName()));
		}
	} else {
		query << "INSERT INTO buddy_invites (charid, buddyid, buddyname) VALUES ('" << buddyid << "', '" << player->getID() << "', '" << player->getName() << "')";
		query.execute();
	}
	MySQL::getInstance()->getPool()->release(conn);
	mysqlpp::Connection::thread_end();
	player->send(PacketCreator().buddyList(player));
}

void Buddies::remove(int charid) {
	if (buddies.find(charid) == buddies.end()) {
		return;
	}

	mysqlpp::Connection::thread_start();
	mysqlpp::Connection* conn = MySQL::getInstance()->getPool()->grab();
	mysqlpp::Query query = conn->query();
	query << "DELETE FROM buddylist WHERE charid = " << player->getID() << " AND buddyid = " << charid;
	query.execute();

	Player* buddy = player->getChannel()->getWorld()->getPlayerByID(charid);
	if (buddy) {
		if (buddy->getBuddyList()->getBuddy(player->getID())) {
			buddy->getBuddyList()->getBuddy(player->getID())->setChannel(-1);
			buddy->send(PacketCreator().buddyList(buddy));
		}
	}
	buddies.erase(charid);
	MySQL::getInstance()->getPool()->release(conn);
	mysqlpp::Connection::thread_end();
	player->send(PacketCreator().buddyList(player));
}

void Buddies::changeChannel(Player *buddy, int playerid, int channel) {
	if(buddy->getBuddyList()->getBuddy(playerid)) {
		buddy->getBuddyList()->getBuddy(playerid)->setChannel(channel);
	}
	buddy->send(PacketCreator().updateBuddyChannel(playerid, channel));
}